export const jsonParse = function (value: string, defaultValue?: Record<string, unknown>) {
    if (typeof value !== 'string') {
        return defaultValue
    }
    try {
        return JSON.parse(value)
    } catch (error) {
        console.error('Error parsing JSON:', error)
        return defaultValue
    }
}
export const jsonStringify = function (
    value: unknown,
    replacer?: undefined | (number | string)[] | null
) {
    try {
        return JSON.stringify(value, replacer) || ''
    } catch (error) {
        console.error('Error stringify JSON:', error)
        return ''
    }
}

export const isAbsoluteURL = function (url: string) {
    return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url)
}
export const combineURLs = function (baseURL: string, relativeURL: string) {
    return relativeURL
        ? baseURL.replace(/\/?\/$/, '') + '/' + relativeURL.replace(/^\/+/, '')
        : baseURL
}

export const buildFullPath = function (requestedURL: string, baseURL?: string) {
    if (baseURL && !isAbsoluteURL(requestedURL)) {
        return combineURLs(baseURL, requestedURL)
    }
    return requestedURL
}

export const transformData = function (
    data: any,
    responseType: 'arraybuffer' | 'document' | 'json' | 'text' | 'stream'
) {
    if (typeof data === 'string' && responseType === 'json') {
        return jsonParse(data)
    }
    return data
}
const isObject = (value: any): value is object => {
    return !!value && value.constructor === Object
}
export const merge = <X extends Record<string | symbol | number, any>>(
    initial: X,
    override: X
): X => {
    if (!initial || !override) return initial ?? override ?? {}

    return Object.entries({ ...initial, ...override }).reduce((acc, [key, value]) => {
        return {
            ...acc,
            [key]: (() => {
                if (isObject(initial[key])) return merge(initial[key], value)
                return value
            })()
        }
    }, {} as X)
}

export const objectToQueryString = (obj: Record<string, any>) => {
    const params = new URLSearchParams()
    for (const key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
            params.append(key, obj[key])
        }
    }
    return params.toString()
}

export const transformGetUrl = function (url: string, params: Record<string, any>) {
    const urlObj = new URL(url)
    if (urlObj.search) {
        return `${url}&${objectToQueryString(params)}`
    }
    if (url.slice(-1) === '?') {
        return `${url}${objectToQueryString(params)}`
    }
    return `${url}?${objectToQueryString(params)}`
}
